﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SIA.Configurators;
using System.Net.Sockets;

namespace SIA.HwAccess.PLCSiemens.ConnectionDriver
{
    public class TCPFetchConnection : TCPClientConnection
    {
        protected CompactHwAddressCollection _readAddressCollection = new CompactHwAddressCollection();
        private IDictionaryProperty _listTagProperty;

        public TCPFetchConnection(IDictionaryProperty ConnectionProperty, IDictionaryProperty listTagProperty)
            : base(ConnectionProperty, listTagProperty)
        {
            this._listTagProperty = listTagProperty;
            foreach (IDictionaryProperty tagP in listTagProperty.Values)
                if (tagP["CONNESSIONE"].PropertyValue == ConnectionProperty["NOME"].PropertyValue)
                    _readAddressCollection.Add(new S7HwAddress(tagP["INDIRIZZO"].PropertyValue).Round2Word() );

            foreach (IHwAddress hwAddress in _readAddressCollection)
            {
                if (!_rawData.ContainsKey(hwAddress.DataKey))
                    _rawData.Add(hwAddress.DataKey, new Byte[4096]);
                if (_rawData[hwAddress.DataKey].Length < (hwAddress.StartByte + hwAddress.LenByte))
                    _rawData[hwAddress.DataKey] = new Byte[4096];
            }
       
        }

        public override void update()
        {
            if (_socket == null || !_socket.Connected) 
                connect();
            if (_socket == null || !_socket.Connected)
            {
                _status = eConnectionStatus.ERROR;
                return;
            }
            foreach (IHwAddress hwAddress in _readAddressCollection)
                readRawData(hwAddress);           
        }
      
        private void readRawData(IHwAddress hwAddress)
        {
            try
            {
                //Verifica connessione attiva
                if (_socket == null || !_socket.Connected)
                {
                    _status = eConnectionStatus.ERROR;
                    return;
                }

                //Recupero header per il recupero dei dati
                Byte[] sendRequest = S7Metods.GetHeaderRead((byte)hwAddress.DataBlock, hwAddress.StartByte, hwAddress.LenByte / 2);
                //Invio richiesta dati
                _socket.Send(sendRequest, SocketFlags.None);

                // Recive Data: buffer singola ricezione         i primi 16 byte sono l'intestazione
                Byte[] bytesReceived = new Byte[hwAddress.LenByte + 16];
                // Buffer Ricezione
                List<Byte> reciveBuffer = new List<Byte>();
                // Byte Letti
                int bytes = 0;
                // DataOra Timeout
                DateTime d = DateTime.Now.AddSeconds(10);

                // Loop ricezione dati
                do
                {
                    //Condizione di Errore: Timeout ricezione
                    if (DateTime.Now > d) throw new Exception("S7Socket.readData: Timeout socket.Recive");
                    //Ricezione dati
                    bytes = _socket.Receive(bytesReceived);
                    //Copia dei dati nel buffer
                    reciveBuffer.AddRange(bytesReceived);
                    //Condizione di uscita: Tutti i dati ricevuti
                    if (reciveBuffer.Count >= hwAddress.LenByte + 16) break;
                }
                while (bytes > 0);

                //Controllo integrita'
                for (int i = 0; i < S7Metods.FetchResponse.Length; i++)
                    if (S7Metods.FetchResponse[i] != reciveBuffer[i])
                        throw new Exception("S7Socket.readData: Errore di comunicazione. ID:" + reciveBuffer[8]);

                //Verifico se la chiave e' presente
                if (!_rawData.ContainsKey(hwAddress.DataKey))
                    _rawData.Add(hwAddress.DataKey, new Byte[4096]);

                //Verifico la dimensione 
                if (_rawData[hwAddress.DataKey].Length < (hwAddress.LenByte + hwAddress.StartByte + 2))
                    _rawData[hwAddress.DataKey] = new Byte[4096];
               
                //Salvo i dati ricevuti
                Byte[] bs = reciveBuffer.GetRange(16, reciveBuffer.Count - 16).ToArray();
                for (int i = 0; i < bs.Length && i < hwAddress.LenByte; i++)
                    _rawData[hwAddress.DataKey][i + hwAddress.StartByte] = bs[i];                  

            }
            catch (Exception ex)
            {
                _info = "i:" + ex.Message;  
                this._status = eConnectionStatus.ERROR;
                SIA.Messages.MessageManager.sendMessage(this, "FetchPassivo", ex);
            }
        }

        /// <summary>Utilizzato per aggiungere un nuovo segnale in lettura</summary>
        /// <param name="signal"></param>
        public override void register(IHwSignal signal)
        {
            if (signal is S7Signal)
                if (!_signals.ContainsKey(signal.Name))
                {
                    IHwAddress ha = ((S7Signal)signal).Address;
                    _signals.Add(signal.Name, signal);
                    _readAddressCollection.Add(((S7HwAddress)ha).Round2Word());
                    if (!_rawData.ContainsKey(ha.DataKey))
                        _rawData.Add(ha.DataKey, new Byte[4096]);
                    if (_rawData[ha.DataKey].Length < (ha.StartByte + ha.LenByte))
                        _rawData[ha.DataKey] = new Byte[4096];
                    signal.Connection = this;
                }
        }
        new public String ToString()
        {
            return base.ToString() + " " + _info + " Interval: " + _timer.Interval;
        }

    }
}
